package Chapter25;

public class MyLinkedList<E> extends MyAbstractList<E> {
    // 定义node节点类
    private static class Node<E> {
        E element;
        Node<E> next;

        public Node(E element) {
            this.element = element;
        }
    }

    private Node<E> head, tail;

    public MyLinkedList() {

    }

    public MyLinkedList(E[] objects) {
        super(objects);
    }

    public E getFirst() {
        if (size == 0) {
            return null;
        } else {
            return head.element;
        }
    }

    public E getLast() {
        if (size == 0) {
            return null;
        } else {
            return tail.element;
        }
    }

    public void addFirst(E e) {
        Node<E> newNode = new Node<E>(e);
        newNode.next = head;
        head = newNode;
        size++;

        if (tail == null) {
            tail = head;
        }
    }

    public void addLast(E e) {
        Node<E> newNode = new Node<E>(e);

        if (tail == null) {
            head = tail = newNode;
        } else {
            tail.next = newNode;
            tail = tail.next;
        }
        size++;
    }

    public void add(int index, E e) {
        if (index == 0)
            addFirst(e);
        else if (index >= size)
            addLast(e);
        else {
            Node<E> current = head;
            for (int i = 1; i < index; i++) {
                current = current.next;
            }
            Node<E> temp = current.next;
            current.next = new Node<E>(e);
            (current.next).next = temp;
        }
    }

    public E removeFirst() {
        if (size == 0) {
            return null;
        } else {
            head = head.next;
            size--;
            return head.element;
        }

    }

    public E removeLast() {
        if (size == 0)
            return null;
        else if (size == 1) {
            Node<E> temp = head;
            head = tail = null;
            return temp.element;
        } else {
            Node<E> current = head;
            for (int i = 0; i < size - 2; i++)
                current = current.next;
            Node<E> temp = tail;
            tail = current;
            current.next = null;
            size--;
            return temp.element;
        }
    }

    public E remove(int index) {
        if (index < 0 || index >= size)
            return null;
        else if (index == 0) return removeFirst();
        else if (index == size - 1) return removeLast();
        else {
            Node<E> previous = head;
            for (int i = 1; i < index; i++) {
                previous = previous.next;
            }

            Node<E> current = previous.next;
            previous.next = current.next;
            size--;
            return current.element;
        }
    }

    public String toString() {
        StringBuilder result = new StringBuilder("[");

        Node<E> current = head;
        for (int i = 0; i < size; i++) {
            result.append(current.element);
            current = current.next;
            if (current != null) {
                result.append(", ");
            } else {
                result.append("]");
            }
        }
        return result.toString();
    }

    public void clear() {
        head = tail = null;
    }

    public boolean contains(E e) {
        boolean isContains = false;
        if (size <= 0) {
            return isContains;
        }
        Node<E> current = head;
        for (int i = 0; i < size; i++) {
            if (e.equals(current.element)) {
                isContains = true;
            }
            current = current.next;
        }
        return isContains;
    }

    public E get(int index) {
        return head.element;
    }

    public int indexOf(E e) {
        int index = -1;
        if (size <= 0) {
            return index;
        }
        Node<E> current = head;
        for (int i = 0; i < size; i++) {
            if (e.equals(current.element)) {
                index = i;
                break;
            }
            current = current.next;
        }
        return index;
    }

    public int lastIndexOf(E e) {
        return 0;
    }

    public E set(int index, E e) {
        Node<E> newNode = new Node<E>(e);
        Node<E> theOldNode = null;
        if (size == 0 || index == 0) {
            return null;
        } else if (size == 1) {
            head = tail = newNode;
        } else if (index == 0) {
            theOldNode = head;
            newNode.next = head;
            head = newNode;
        } else if (index == 1) {
            theOldNode = head.next;
            newNode.next = head.next;
            head.next = newNode;
        } else if (index >= size - 1) {
            Node<E> current = head;
            for (int i = 0; i < size - 2; i++) {
                current = current.next;
            }
            theOldNode = current.next;
            current.next = newNode;
        } else {
            Node<E> current = head;
            for (int i = 0; i < index - 1; i++) {
                current = current.next;
            }
            theOldNode = current.next;
            newNode = theOldNode.next;
            current.next = newNode;
        }
        return theOldNode.element;
    }
}
